package me.zhengjie.common.utils

import cn.hutool.core.io.resource.ClassPathResource
import eu.bitwalker.useragentutils.UserAgent
import jakarta.servlet.http.HttpServletRequest

import org.hibernate.query.sqm.tree.SqmNode.log
import org.lionsoul.ip2region.DataBlock
import org.lionsoul.ip2region.DbConfig
import org.lionsoul.ip2region.DbSearcher
import org.springframework.core.io.ResourceLoader
import java.io.IOException
import java.net.InetAddress
import java.net.UnknownHostException
import java.util.*
import java.util.concurrent.TimeUnit


/**
 * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
 */
object StringUtils : org.apache.commons.lang3.StringUtils() {
    //private final StringUtils log = org.slf4j.LoggerFactory.getLogger(RedisConfig::class.java)
    private const val SEPARATOR = '_'

    /*fun isNotBlank(str: String?): Boolean {
        return org.apache.commons.lang3.StringUtils.isNotBlank(str)
    }*/
    /*fun isBlank(cs: CharSequence): Boolean {
        return org.apache.commons.lang3.StringUtils.isBlank(cs)
    }
    fun <T> join(vararg elements: T): String {
        return org.apache.commons.lang3.StringUtils.join(elements)
    }
    fun isEmpty(str:String?):Boolean{
        return org.apache.commons.lang3.StringUtils.isEmpty(str)
    }*/
    @JvmStatic
    fun shortUUIDGenerate(): String {
        val chars = arrayOf(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0",
            "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
        )
        val shortBuffer = StringBuffer()
        val uuid = UUID.randomUUID().toString().replace("-", "")
        for (i in 0..7) {
            val str = uuid.substring(i * 4, i * 4 + 4)
            val x = str.toInt(16)
            shortBuffer.append(chars[x % 0x3E])
        }
        return shortBuffer.toString().uppercase()
    }

    /**
     * 驼峰命名法工具
     *
     * @return toCamelCase(" hello_world ") == "helloWorld"
     * toCapitalizeCamelCase("hello_world") == "HelloWorld"
     * toUnderScoreCase("helloWorld") = "hello_world"
     */
    @JvmStatic
    fun toCamelCase(s: String?): String? {
        var s = s ?: return null
        s = s.lowercase(Locale.getDefault())
        val sb = StringBuilder(s.length)
        var upperCase = false
        for (i in 0 until s.length) {
            val c = s[i]
            if (c == SEPARATOR) {
                upperCase = true
            } else if (upperCase) {
                sb.append(c.uppercaseChar())
                upperCase = false
            } else {
                sb.append(c)
            }
        }
        return sb.toString()
    }

    /**
     * 驼峰命名法工具
     *
     * @return toCamelCase(" hello_world ") == "helloWorld"
     * toCapitalizeCamelCase("hello_world") == "HelloWorld"
     * toUnderScoreCase("helloWorld") = "hello_world"
     */
    @JvmStatic
    fun toCapitalizeCamelCase(s: String?): String? {
        var s: String? = s ?: return null
        s = toCamelCase(s)
        return s!!.substring(0, 1).uppercase(Locale.getDefault()) + s.substring(1)
    }

    /**
     * 驼峰命名法工具
     *
     * @return toCamelCase(" hello_world ") == "helloWorld"
     * toCapitalizeCamelCase("hello_world") == "HelloWorld"
     * toUnderScoreCase("helloWorld") = "hello_world"
     */
    @JvmStatic
    fun toUnderScoreCase(s: String?): String? {
        if (s == null) {
            return null
        }
        val sb = StringBuilder()
        var upperCase = false
        for (i in 0 until s.length) {
            val c = s[i]
            var nextUpperCase = true
            if (i < s.length - 1) {
                nextUpperCase = Character.isUpperCase(s[i + 1])
            }
            upperCase = if (i > 0 && Character.isUpperCase(c)) {
                if (!upperCase || !nextUpperCase) {
                    sb.append(SEPARATOR)
                }
                true
            } else {
                false
            }
            sb.append(c.lowercaseChar())
        }
        return sb.toString()
    }

    /**
     * 获取ip地址
     */
    @JvmStatic
    fun getIp(request: HttpServletRequest?): String? {
        var ip = request!!.getHeader("x-forwarded-for")
        if (ip == null || ip.length == 0 || "unknown".equals(ip, ignoreCase = true)) {
            ip = request.getHeader("Proxy-Client-IP")
        }
        if (ip == null || ip.length == 0 || "unknown".equals(ip, ignoreCase = true)) {
            ip = request.getHeader("WL-Proxy-Client-IP")
        }
        if (ip == null || ip.length == 0 || "unknown".equals(ip, ignoreCase = true)) {
            ip = request.remoteAddr
        }
        if (ip!!.contains(",")) {
            ip = ip.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
        }
        if ("127.0.0.1" == ip) {
            // 获取本机真正的ip地址
            try {
                ip = InetAddress.getLocalHost().hostAddress
            } catch (e: UnknownHostException) {
                e.printStackTrace()
            }
        }
        return ip
    }

    /**
     * 根据ip获取详细地址
     */
    @JvmStatic
    fun getCityInfo(ip: String?): String {
        try {
            // 1、创建 searcher 对象
            //"classpath:/META-INF/resources/main/ip2region/ip2region.db"
//            val dbPath = javaClass.classLoader.getResource("ip2region/ip2region.db").file
//            var searcher: Searcher? = null
//            searcher = try {
//                Searcher.newWithFileOnly(dbPath)
//            } catch (e: IOException) {
//                //System.out.printf("failed to create searcher with `%s`: %s\n", dbPath, e);
//                log.error("failed to create searcher with `%s`: %s\n", dbPath, e)
//                // 3、关闭资源
//                searcher!!.close()
//                return ""
//            }
//            // 2、查询
//            return try {
//                val sTime = System.nanoTime()
//                val region = searcher!!.search(ip)
//                val cost = TimeUnit.NANOSECONDS.toMicros((System.nanoTime() - sTime))
//                //System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost);
//                log.info("{region: ${region}, ioCount: ${arrayOf(searcher.ioCount)}, took: ${cost} μs}\n")
//                var address =""
//                if (region!=null) {
//                    var address = region.replace("0|", "")
//                    if (address[address.length - 1] == '|') {
//                        address = address.substring(0, address.length - 1)
//                    }
//                    if (address == ElAdminConstant.REGION) address="内网IP" else address
//                }else{
//                    address = "内网IP"
//                }
//                // 3、关闭资源
//                searcher.close()
//
//                return address
//
//            } catch (e: Exception) {
//                //System.out.printf("failed to search(%s): %s\n", ip, e);
//                log.error("failed to search(%s): %s\n", ip, e)
//                // 3、关闭资源
//                searcher!!.close()
//                "内网IP"
//            }


            // 备注：并发使用，每个线程需要创建一个独立的 searcher 对象单独使用。

            var path = "ip2region/ip2region.db";
            var name = "ip2region.db";
            val config:DbConfig =  DbConfig();
            val file = FileUtil.inputStreamToFile(ClassPathResource(path).getStream(), name)
            val searcher:DbSearcher = DbSearcher(config, file.getPath())
            val method = searcher.javaClass.getMethod("btreeSearch", String::class.java)
            val dataBlock: DataBlock = method.invoke(searcher, ip) as DataBlock
            var address = dataBlock.getRegion().replace("0|","")
            if(address[address.length-1] == '|'){
                address = address.substring(0,address.length - 1);
            }
            if (address == ElAdminConstant.REGION) address="内网IP" else address
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }

    @JvmStatic
    fun getBrowser(request: HttpServletRequest?): String {
        val userAgent = UserAgent.parseUserAgentString(
            request!!.getHeader("User-Agent")
        )
        val browser = userAgent.browser
        return browser.getName()
    }

    @JvmStatic
    val weekDay: String
        /**
         * 获得当天是周几
         */
        get() {
            val weekDays = arrayOf("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
            val cal = Calendar.getInstance()
            cal.time = Date()
            var w = cal[Calendar.DAY_OF_WEEK] - 1
            if (w < 0) {
                w = 0
            }
            return weekDays[w]
        }
}